home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / vt100tst.arc / VT100.C next >
Text File  |  1985-12-12  |  8KB  |  354 lines

  1. /*
  2. Having received many requests for my terminal emulator for the IBM PC,
  3. here it is. It is written in C for the DeSmet C compiler, with assembler
  4. for all the I/O routines. DeSmet's I/O library is big as a bus, and slow
  5. to boot, so I simply avoid it. This program does very little, reasonably
  6. well. New functions are easy to add. For folks with other compilers,
  7. the only part likely to fail to work is the assembler for I/O: I put it
  8. in-stream, using the "#asm" construct for in-stream assembler. You will
  9. need to edit all assembler into an external assembler file, and invent
  10. headers and trailers to implement the C calling convention for your compiler.
  11. This program hasn't been prettied up for public consumption, but I am
  12. painfully busy with other things, so in the hope that this is better
  13. than nothing, here it is:
  14.  
  15. >From this to the next line of dashes is the document file for the program: */
  16. /*------------------------------------------------------------------------------
  17.  
  18.  
  19.  
  20.                  Comm: a communication program for the IBM-PC
  21.  
  22. Comm is a minimal dumb terminal emulator for the IBM-PC under PC-DOS.  It  uses
  23. BIOS  function calls for keyboard input,  allowing all control characters to be
  24. sent with the conventional keyboard sequences. It uses an interrupt handler for
  25. the communication port,  functional up to 9600 baud.  It is written in  C  with
  26. assembler routines to handle I/O. It only supports the first asynchronous port,
  27. COM1:.  It doesn't support setting the communication parameters.  This  can  be
  28. done with the DOS "mode" command. The port IS NOT DISABLED (DTR is not dropped)
  29. when the program is terminated; you must disconnect from the remote computer in
  30. some other fashion.  As a result, however, you can exit to DOS, make use of any
  31. DOS commands which don't tinker with the communication  port,  and  resume  the
  32. terminal  session,  without any disruption visible at the other end (characters
  33. sent to the PC will be lost in the interim).  Best of  all,  it  is  small.  It
  34. supports very few commands, all of which are alt sequences:
  35.  
  36. alt-e is a toggle:  it turns echoing on and off (default off). This can be used
  37.       for half-duplex systems.
  38.  
  39. alt-v is a toggle:  it turns verbose mode on and off (default off).  In verbose
  40.       mode  characters  which  are  normally non-printable and aren't "carriage
  41.       control" characters print as "^x",  where "x" is the character you  would
  42.       hit to send the control character. Otherwise such chaff is ignored.
  43.  
  44. alt-b sends a break (approx. 300 ms. of line high)
  45.  
  46. alt-q quits the program, and returns to DOS
  47. ------------------------------------------------------------------------------
  48. The program follows:
  49. NOTE: this code is indented using tabs set every 4 columns, not 8.
  50. ------------------------------------------------------------------------------*/
  51. /*
  52.  * Rudimentary communication program; written in C with I/O
  53.  * routines in assembler, using "#asm" construct in DeSmet C.
  54.  */
  55.  
  56. #define TRUE 1
  57. #define FALSE 0
  58. #define NULL 0
  59.  
  60. #define comm_stat head!=tail
  61.  
  62. int head=0,
  63.     tail=0;
  64.  
  65. char comm_buffer[8192];
  66.  
  67. main()
  68. {
  69.     char commget();
  70.  
  71.     int c,
  72.         echo=FALSE,
  73.         verbose=FALSE;
  74.  
  75.     initcomm();
  76.  
  77.     goto inside;
  78.     while((c=my_ci())<256) /* alt's and function keys are >=256 */
  79.     {
  80.         commput(c);
  81.         if(echo)
  82.             my_co(c);
  83. inside:    while(my_stat()==0)
  84.             if(comm_stat)
  85.                 if(is_nice(c=commget()))
  86.                     my_co(c);
  87.                 else
  88.                     if(verbose)
  89.                     {
  90.                         my_co('^');
  91.                         my_co(127&(c+'@'));
  92.                     }
  93.     }
  94.     switch(c>>8) /* process function key */
  95.     {
  96.         case '\060': /* b    send break    */
  97.             make_break();
  98.             my_puts("** break **\n");
  99.             break;
  100.         case '\022': /* e    echo toggle    */
  101.             echo = !echo;
  102.             if(echo)
  103.                 my_puts("** echo on **\n");
  104.             else
  105.                 my_puts("** echo off **\n");
  106.             break;
  107.         case '\020': /* q    quit        */
  108.             my_puts("** returning to DOS **\n");
  109.             goto byebye;
  110.         case '\057': /* v    verbose        */
  111.             verbose = !verbose;
  112.             if(verbose)
  113.                 my_puts("** verbose on **\n");
  114.             else
  115.                 my_puts("** verbose off **\n");
  116.             break;
  117.     }
  118.     goto inside;
  119.  
  120. byebye:
  121.     killcomm();
  122. }
  123.  
  124. initcomm()
  125. {
  126. #asm
  127.  
  128. ; initialize communication port,
  129. ; and install interrupt handler
  130.  
  131. ; save dseg for interrupt handler
  132.     mov        ax,ds
  133.     mov        cs:dssave,ax
  134.  
  135. ; set int vector to my handler
  136.     push    ds
  137.     xor        ax,ax
  138.     mov        ds,ax
  139.     mov        [30h],offset handler
  140.     mov        ax,cs
  141.     mov        [32h],ax
  142.     pop        ds
  143.  
  144. ; assert DTR, RTS, and OUT2
  145.     mov        dx,3fch
  146.     mov        al,11
  147.     out        dx,al
  148.  
  149. ; enable interrupts for data ready
  150.     mov        dx,3f9h
  151.     mov        al,1
  152.     out        dx,al
  153.  
  154. ; clear any outstanding int
  155.     mov        dx,3f8h
  156.     in        al,dx
  157.  
  158. ; enable interrupts
  159.     sti
  160.  
  161. ; enable IRQ4 on 8259A
  162.     in        al,21h
  163.     and        al,0efh
  164.     out        21h,al
  165.  
  166. ; and return
  167.     jmp        init_finis
  168.  
  169. dssave:    dw 0
  170.  
  171. handler:
  172.     push    ds
  173.     push    ax
  174.     push    dx
  175.     push    bx
  176.  
  177. ; restore appropriate dseg
  178.     mov        ax,cs:dssave
  179.     mov        ds,ax
  180.  
  181. ; grab the byte from comm port
  182.     mov        dx,3f8h
  183.     in        al,dx
  184.  
  185. ; put it in the buffer
  186.     mov        bx,tail_
  187.     mov        comm_buffer_[bx],al
  188.  
  189. ; tail=tail+1 (mod 8192)
  190.     inc        bx
  191.     cmp        bx,8192
  192.     jl        handler_around
  193.     xor        bx,bx
  194.  
  195. handler_around:
  196.     mov        tail_,bx
  197.  
  198. ; tell the 8259A EOI
  199.     mov        dx,20h
  200.     mov        al,32
  201.     out        dx,al
  202.  
  203.     pop        bx
  204.     pop        dx
  205.     pop        ax
  206.     pop        ds
  207.  
  208. ; reenable interrupts
  209.     sti
  210.  
  211.     iret
  212.  
  213. init_finis:
  214. #
  215. }
  216.  
  217. commput(c)
  218. int c;
  219. {
  220. #asm
  221. ; put the character out the port
  222.     mov        dx,3f8h
  223.     mov        ax,[bp+4]
  224.     out        dx,al
  225. #
  226. }
  227.  
  228. char commget()
  229. {
  230.     char temp;
  231.  
  232.         temp=comm_buffer[head++];
  233.         head%=8192;
  234.         return(temp);
  235. }
  236.  
  237. killcomm()
  238. {
  239. #asm
  240. ; disconnect the interrupt handler
  241.     in        al,21h
  242.     or        al,10h
  243.     out        21h,al
  244. #
  245. }
  246.  
  247. make_break()
  248. {
  249. #asm
  250. ; set bit on LCR
  251.     mov        dx,3fbh
  252.     in        al,dx
  253.     push    ax
  254.     or        al,40h
  255.     out        dx,al
  256.  
  257. ; wait a wee bit (~200 ms)
  258.     mov        bx,8
  259. outer:
  260.     mov        cx,7000
  261. tight:
  262.     loop    tight
  263.     dec        bx
  264.     jnz        outer
  265.  
  266. ; and turn break back off
  267.     pop        ax
  268.     out        dx,al
  269. #
  270. }
  271.  
  272. is_nice(c) /* true for those characters that "should" be received */
  273. char c;
  274. {
  275.     c&=127;
  276.     if(c>=' ' && c<='~')    /* printable */
  277.         return(TRUE);
  278.     if(c>6 && c<11)            /* BEL, BS, HT, LF */
  279.         return(TRUE);
  280.     if(c==13 || c==27)        /* CR, ESC */
  281.         return(TRUE);
  282.     return(FALSE);
  283. }
  284.  
  285. my_puts(s) /* puts, using my_co() */
  286. char *s;
  287. {
  288.     while(*s)
  289.     {
  290.         if(*s=='\n')
  291.             my_co('\r');
  292.         my_co(*(s++));
  293.     }
  294. }
  295.  
  296. my_co(c) /* character output, smaller and faster than DeSmet's,
  297.             using DOS function call 2.00 */
  298. char c;
  299. {
  300. #asm
  301.     mov        ah,2
  302.     mov        dx,[bp+4]
  303.     int        21h
  304. #
  305. }
  306.  
  307. my_stat() /* true if character is ready from keyboard */
  308. {
  309. #asm
  310.     mov        ah,1
  311.     int        16h
  312.     jz        stat_no_char
  313.     mov        ax,1
  314.     jmp        stat_finis
  315.  
  316. stat_no_char:
  317.     xor        ax,ax
  318.  
  319. stat_finis:
  320. #
  321. }
  322.  
  323. my_ci() /* get character from keyboard, using BIOS function call */
  324. {
  325. #asm
  326.     xor        ah,ah
  327.     int        16h
  328.     or        al,al
  329.     jz        my_ci_finis
  330.     xor        ah,ah
  331.  
  332. my_ci_finis:
  333. #
  334. }
  335. ------------------------------------------------------------------------------
  336. The termcap for DOS 2.00 with ansi device driver follows:
  337. ------------------------------------------------------------------------------
  338. pm|pcmon|IBM-PC using DOS 2.00 ansi device driver (monochrome)|\
  339.     :am:bc=^H:bw:ce=\E[K:cl=\E[2J:cm=\E[%i%d;%dH:co#80:cr=^M:\
  340.     :do=^J:ho=\E[H:kb=^H:li#25:ll=\E[25H:nd=\E[C:\
  341.     :pt:se=\E[0m:so=\E[1m:ta=^I:up=\E[A:xt:
  342. pc|pccol|IBM-PC using DOS 2.00 ansi device driver (color)|\
  343.     :am:bc=^H:bw:ce=\E[K:cl=\E[2J:cm=\E[%i%d;%dH:co#80:cr=^M:\
  344.     :do=^J:ho=\E[H:kb=^H:li#25:ll=\E[25H:nd=\E[C:\
  345.     :pt:se=\E[0;32m:so=\E[1m:ta=^I:up=\E[A:xt:
  346. ------------------------------------------------------------------------------
  347. and that's it! Enjoy. I place this in the public domain, and would appreciate
  348. feedback. Improvements and bug reports especially desired. If the code is too
  349. cryptic or uncommented, feel free to send questions to:
  350.                     Bennett Todd
  351.                     ...{decvax,ihnp4,akgua}!mcnc!ecsvax!bet
  352.  
  353.  
  354.